﻿using System;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchUtils.Utils;

namespace YJKArchUtils.Common
{
	public class LoopEdge
	{
		public XYZ StartPoint
		{
			get
			{
				return this.m_StartPoint;
			}
			set
			{
				this.ResetBulge(value, this.EndPoint);
				this.m_StartPoint = value;
			}
		}

		public XYZ EndPoint
		{
			get
			{
				return this.m_EndPoint;
			}
			set
			{
				this.ResetBulge(this.StartPoint, value);
				this.m_EndPoint = value;
			}
		}

		public double Bulge
		{
			get
			{
				return this.m_Bulge;
			}
		}

		public bool IsArc
		{
			get
			{
				return !Geometry.IsEqual(this.m_Bulge, 0.0);
			}
		}

		public ElementId CurveId
		{
			get
			{
				return this.m_CurveId;
			}
		}

		public LoopEdge.EdgeType TheEdgeType
		{
			get
			{
				return this.m_EdgeType;
			}
			set
			{
				this.m_EdgeType = value;
			}
		}

		public LoopEdge(LoopEdge rhs)
		{
			this.m_StartPoint = rhs.m_StartPoint;
			this.m_EndPoint = rhs.m_EndPoint;
			this.m_Bulge = rhs.m_Bulge;
			this.m_CurveId = rhs.m_CurveId;
			this.m_EdgeType = rhs.m_EdgeType;
		}

		public LoopEdge(XYZ startPoint, XYZ endPoint, double bulge, ElementId curveId, LoopEdge.EdgeType edgeType)
		{
			this.m_StartPoint = startPoint;
			this.m_EndPoint = endPoint;
			this.m_Bulge = bulge;
			this.m_CurveId = curveId;
			this.m_EdgeType = edgeType;
		}

		public LoopEdge(Curve curveIn, LoopEdge.EdgeType edgeType = LoopEdge.EdgeType.ET_Extensible, bool bConverse = false, ElementId curveId = null)
		{
			this.m_StartPoint = curveIn.GetEndPoint(0);
			this.m_EndPoint = curveIn.GetEndPoint(1);
			this.m_Bulge = 0.0;
			Arc arc = curveIn as Arc;
			if (arc != null)
			{
				XYZ center = arc.Center;
				double num = Geometry.GetBulge(this.m_StartPoint, this.m_EndPoint, center, true);
				if (!arc.Normal.IsAlmostEqualTo(XYZ.BasisZ))
				{
					num *= -1.0;
				}
				this.m_Bulge = num;
			}
			if (bConverse)
			{
				this.m_StartPoint = curveIn.GetEndPoint(1);
				this.m_EndPoint = curveIn.GetEndPoint(0);
				this.m_Bulge *= -1.0;
			}
			this.m_CurveId = curveId;
			this.m_EdgeType = edgeType;
		}

		public Curve GetCurve()
		{
			if (this.IsArc)
			{
				XYZ ptCenter = this.Center();
				XYZ xyz = Geometry.CalculatMidPoint(this.StartPoint, this.EndPoint, ptCenter, this.Normal());
				return Arc.Create(this.StartPoint, this.EndPoint, xyz);
			}
			return YJKLineEx.YJKGetBound(this.StartPoint, this.EndPoint);
		}

		public XYZ Center()
		{
			if (!this.IsArc)
			{
				return null;
			}
			XYZ result = null;
			Geometry.GetCenterWithBulge(this.StartPoint, this.EndPoint, this.Bulge, ref result);
			return result;
		}

		public XYZ Normal()
		{
			if (!this.IsArc)
			{
				return null;
			}
			if (Geometry.GreaterThan(this.Bulge, 0.0))
			{
				return XYZ.BasisZ;
			}
			return -XYZ.BasisZ;
		}

		public void SetElevation(double elevation)
		{
			this.m_StartPoint = new XYZ(this.m_StartPoint.X, this.m_StartPoint.Y, elevation);
			this.m_EndPoint = new XYZ(this.m_EndPoint.X, this.m_EndPoint.Y, elevation);
		}

		public Curve ConvertToCurve(Autodesk.Revit.ApplicationServices.Application app)
		{
			Curve result;
			try
			{
				if (this.IsArc)
				{
					XYZ ptCenter = this.Center();
					XYZ radianPnt = Geometry.CalculatMidPoint(this.StartPoint, this.EndPoint, ptCenter, this.Normal());
					result = app.CreatYJKArc(this.StartPoint, this.EndPoint, radianPnt);
				}
				else
				{
					result = YJKLineEx.YJKGetBound(this.StartPoint, this.EndPoint);
				}
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		private void ResetBulge(XYZ newStartPoint, XYZ newEndPoint)
		{
			if (!this.IsArc)
			{
				return;
			}
			XYZ centerPt = null;
			Geometry.GetCenterWithBulge(this.StartPoint, this.EndPoint, this.Bulge, ref centerPt);
			this.m_Bulge = Geometry.GetBulge(newStartPoint, newEndPoint, centerPt, Geometry.GreaterThan(this.Bulge, 0.0));
		}

		public void Move(XYZ offset)
		{
			this.m_StartPoint += offset;
			this.m_EndPoint += offset;
		}

		private XYZ m_StartPoint;

		private XYZ m_EndPoint;

		private double m_Bulge;

		private ElementId m_CurveId;

		private LoopEdge.EdgeType m_EdgeType;

		public enum EdgeType
		{
			ET_Fixed,
			ET_Extensible
		}
	}
}
